﻿# -*- encoding: utf-8 -*-
# author： 逐阳
# DateTime: 2023/11/22
import time
import datetime
import requests
import pymysql
from pymysql.cursors import DictCursor
from prettytable import PrettyTable


class Param:
    def __init__(self, store):
        self.did = "f7feb79e-bb14-48fa-9e36-76e809ca8db3"
        self.token = self.loginPortal()
        self.header = {"Cookie": self.token}
        self.store = store

        # 一小时主库
        self.db01 = MyDB("db03.beta1.fn", "su_freshpicking", "FG6tq8BGfc", "fresh_picking", self.store)

        # 一小时分库
        if self.store == "1501":
            self.db02 = MyDB("db01.beta1.fn", "su_freshpicking", "FG6tq8BGfc", "fresh_picking_7", self.store)
        else:
            self.db02 = MyDB("db04.beta1.fn", "su_freshpicking", "FG6tq8BGfc", "fresh_picking_2", self.store)

        self.store_type = self.db01.ifStoreType()
        if self.store_type == "plus-x":
            self.emp_name = "李向迪"
            self.emp_phone = "17683739442"
        else:
            self.emp_name = "尤菊华"
            self.emp_phone = "8"

        # 条码允效期
        year = str(time.localtime().tm_year)[-1]
        self.expiry = year + '365'

    @staticmethod
    def loginPortal():
        url = 'http://sso.beta1.fn/loginApi/auth'
        params = {
            'type': '2',
            'area': '12345',
            'username': "17683739442",
            'password': "x123456"
        }
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                          "AppleWebKit/537.36 (KHTML, like Gecko) "
                          "Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67"
        }

        result = requests.get(url=url, headers=headers, params=params)
        if result.json().get('status') != 1:
            print(result.text)
            raise Exception('portal后台登录失败')
        return 's98r5h2s6v1m37o=' + result.json()['data']['token']

    def code_26(self, item, weight, price='0000000'):
        """26位新磅秤码"""
        # 获得处理后的数据
        items = str(item).zfill(7)
        weights = str(weight).zfill(5)
        beta_code = '3' + items + weights + price + self.expiry

        # 计算校验位C
        a1 = int(beta_code[8]) + int(beta_code[10]) + int(beta_code[12]) + int(beta_code[14]) + int(
            beta_code[16]) + int(beta_code[18])
        b1 = int(beta_code[9]) + int(beta_code[11]) + int(beta_code[13]) + int(beta_code[15]) + int(
            beta_code[17]) + int(beta_code[19])
        c = (10 - ((a1 + b1 * 3) % 10)) % 10

        # 计算校验位D
        beta_code = beta_code + str(c)
        a2, b2 = 0, 0
        for t in range(25):
            if t % 2:
                b2 += int(beta_code[t])
            else:
                a2 += int(beta_code[t])
        d = (10 - ((a2 + b2 * 3) % 10)) % 10

        code_26 = beta_code + str(d)
        return code_26


class Picking(Param):
    def __init__(self, store):
        super().__init__(store)

    def getOrderStatus(self, order):
        url = "http://backend-picking.beta1.fn/originalOrder/getTableList.do"
        datas = {
            "createTimeS": datetime.date.today(),
            "createTimeE": datetime.date.today(),
            "storeNo": self.store,
            "orderNo": order,
            "pickOrderStatus": "",
            "sourceFrom": "",
            "deliveryMerchant": "",
            "waveOrderNo": "",
            "size": 10,
            "page": 1
        }

        result = requests.post(url=url, headers=self.header, data=datas)
        if result.json().get("code") != 200:
            print(result.json())
            raise Exception("原始订单接口异常")

        group_status = result.json().get("data")[0].get("pickOrderStatus")  # 派单状态
        order_status = result.json().get("data")[0].get("shelfTake")  # 订单状态
        if group_status == "3" and order_status == "1":
            print("订单派单完成")
            return 0
        elif group_status == "2":
            print("订单正在下发，请稍等...\n")
            return 300
        elif group_status == "1":
            print("订单正在集批，请稍等...\n")
            return 300
        else:
            return 500

    def getPickItemNo(self, order):
        """
        判断订单是否下发，获得订单数据
        return: list[[拣货区、拣货单号、批次单号]，道口信息] & int
        """
        if self.store_type == "plus-x":
            url = "http://backend-picking.beta1.fn/taoPickOrderShipment/getTableListByDC.do"
        else:
            url = "http://backend-picking.beta1.fn/taoPickOrderShipment/getTableList.do"
        datas = {
            "page": 1,
            "limit": 10,
            "pickStatus": "",
            "pickDate": datetime.date.today(),
            "pickDateMax": datetime.date.today(),
            "pickEmployee": "",
            "orderNo": order,
            "vehicleNo": "",
            "stallNo": "",
            "boxNo": "",
            "sourceFrom": "",
            "waveOrderNo": "",
            "storeNo": self.store
        }

        result = requests.post(url=url, headers=self.header, data=datas)
        if result.json().get("code") != 200:
            print(result.text)
            raise Exception("履约单明细接口查询异常")

        # 判断订单是否下发
        pickOrderInfo = result.json().get("data")
        if pickOrderInfo:
            pick = []
            for i in pickOrderInfo:
                if i.get("pickStatusName") == "待抢单":
                    pick_info = {"waveOrderNo": i.get("waveOrderNo"), "pickOrderNo": i.get("pickOrderNo"),
                                 "pickAreaName": i.get("pickAreaName")}
                    pick.append(pick_info)
                elif i.get("pickStatusName") == "待完成拣货":
                    pick.append(1)
            else:
                location = pickOrderInfo[0].get("stallNo")  # 道口信息
                pick_order = [pick, location]

                if 1 in pick:  # 是否有正在拣货的拣货单
                    pick_order = 1
                elif not pick:  # 没有待抢的拣货单
                    pick_order = 2
        else:
            pick_order = 3

        return pick_order

    def getCarrier(self, box_type, vehicle_type=2):
        """获得载具信息"""
        url = "http://backend-picking.beta1.fn/vehicle/getTableList.do"
        datas = {
            "page": 1,
            "limit": 10,
            "storeId": self.store,
            "vehicleNo": "",
            "enabledStatus": 1,
            "bindingStatus": 0,
            "vehicleType": vehicle_type,
            "boxType": box_type
        }

        result = requests.post(url=url, headers=self.header, data=datas)
        if result.json().get("code") != 200:
            print(result.text)
            raise Exception("载具查询接口异常")

        return result.json().get("data")[0].get("vehicleNo")

    def robAssignOrder(self, pick_no, area_no):
        """抢单"""
        plus_x = "http://tao-picking-plus-x.beta1.fn/api/taoapp/pick/grabPickRepOrders"
        x = "http://tao-picking-x.beta1.fn/api/taoapp/pick/grabPickRepOrders"

        url = plus_x if self.store_type == "plus-x" else x
        datas = {
            "data": '{\"pickOrderNo\": \"%s\", \"pickAreaNo\": \"%s\"}' % (pick_no, area_no),
            "globalInfo": '{\"accountRealName\": \"管理员\", \"accountUserName\": \"admin\", '
                          '\"appType\": \"1\", \"appVersion\": \"3.0.0.0\",\"deviceId\": \"%s\", '
                          '\"employeeName\": \"%s\", \"employeeNo\": \"%s\",\"storeNo\": \"%s\"}' % (
                              self.did, self.emp_name, self.emp_phone, self.store)
        }

        result = requests.post(url=url, data=datas)
        if result.json().get("errorCode") != 0:
            raise Exception(f"抢单接口异常,{result.json().get('errorDesc')}")

    def ifItemInBarcode(self, wave_order_no):
        """根据商品类型生成磅秤码"""
        barcode = []
        differ_weight = 35  # 差异重量
        item_info = self.db02.getItemType(wave_order_no)
        for i in item_info:
            if i.get("product_type") != 1:
                code1 = self.code_26(i.get('rt_no'), str(i.get('product_num'))[:-2])
                if int(i.get('product_num')) > differ_weight:
                    code2 = self.code_26(i.get('rt_no'), int(str(i.get('product_num'))[:-2]) - differ_weight)
                else:
                    code2 = "商品重量小于差异重量，未生成缺重条码"
                barcode.append([code1 + "\n" + code2, i.get('rt_no')])
        return barcode


class MyDB:
    def __init__(self, host, user, password, database, store_no):
        self.host = host
        self.user = user
        self.password = password
        self.database = database
        self.store = store_no

        db_info = self.getBaseDateInfo(self.store)
        self.db_no = db_info.get("db_no")
        self.db_table = db_info.get("table_no")

    @classmethod
    def getBaseDateInfo(cls, store_no):
        """获取分库分表"""
        db_info = {'db_no': 'fresh_picking_2', 'table_no': '25'}
        if str(store_no) == "1001":
            pass
        elif str(store_no) == "1701":
            db_info["table_no"] = "7"
        elif str(store_no) == "3024":
            db_info["db_no"] = "fresh_picking_0"
            db_info["table_no"] = "1"
        elif str(store_no) == "1501":
            db_info["db_no"] = "fresh_picking_7"
            db_info["table_no"] = "21"
        return db_info

    def __enter__(self):
        self.conn = pymysql.connect(
            host=self.host,
            port=3306,
            user=self.user,
            password=self.password,
            database=self.database,
            charset="utf8"
        )
        self.cursor = self.conn.cursor(DictCursor)
        return self

    def select(self, sql, val):
        self.cursor.execute(sql, val)
        result = self.cursor.fetchall()

        return result

    def ifStoreType(self):
        """判断门店类型"""
        sql = "SELECT server_group FROM fresh_picking.db_table_info_tao where store_no = %s;"
        with MyDB(self.host, self.user, self.password, self.database, self.store) as db:
            server = db.select(sql, self.store)

        return server[0].get("server_group")

    def getPickArea(self, area):
        """获得拣货单号信息"""
        sql = "SELECT store_no, pick_area_no, pick_area_name " \
              "FROM mars_pickarea " \
              "WHERE store_no = %s AND STATUS = 1 AND business_type = 1 AND warehouse_no = 10"

        with MyDB(self.host, self.user, self.password, self.database, self.store) as db:
            area_info = db.select(sql, self.store)
            for i in area_info:
                if area == i.get("pick_area_name"):
                    return i.get("pick_area_no")

    def getItemType(self, wave_order_no):
        """获得订单下商品类型、重量"""
        sql = "SELECT distinct rt_no, product_type,product_num FROM " + self.db_no + ".order_goods_info_" + self.db_table + " WHERE wave_order_no = %s"
        val = (wave_order_no,)
        with MyDB(self.host, self.user, self.password, self.database, self.store) as db:
            info = db.select(sql, val)
        return info

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.cursor.close()
        self.conn.close()


def mainPicking(num=0, storeNo=1001):
    try:
        while True:
            # 定义展示列表
            tb = PrettyTable()
            show_title = ["订单号", "当前道口", "可用拣货袋", "可用灰箱", "可用保温箱"]

            # 获取订单/门店
            order = input("请输入订单号：")
            if order in ("1001", "1701", "3024", "1501"):
                storeNo = order
                print(f"门店更新为：{storeNo}\n")
                continue

            pck = Picking(storeNo)

            while True:
                # 判断返回数据是否有效
                order_info = pck.getPickItemNo(order)
                if isinstance(order_info, list):
                    # 获得物流箱信息
                    boxs = []
                    for t in range(1, 3):
                        box = pck.getCarrier(t)
                        boxs.append(box)
                    show_info = [order, order_info[1], False, boxs[0], boxs[1]]

                    # 判断是否有多个拣货单
                    flag = len(order_info[0])
                    for i in order_info[0]:
                        area_no = pck.db01.getPickArea(i.get("pickAreaName"))  # 获得拣货区编号
                        pck.robAssignOrder(i.get("pickOrderNo"), area_no)  # 调用抢单方法

                        # 获得载具信息
                        pick_bag = pck.getCarrier(None, 1)

                        # 首次获得条码信息
                        barcode_info = pck.ifItemInBarcode(order_info[0][0].get("waveOrderNo"))
                        if barcode_info:
                            if not show_info[2]:
                                for bar in barcode_info:
                                    show_title.append(bar[1])
                                    show_info.append(bar[0])

                        # 更换拣货袋
                        show_info[2] = pick_bag

                        # 展示拣货单信息
                        tb.field_names = show_title
                        tb.add_row(show_info)
                        print(tb, end='\n')
                        # print(tb)

                        # 判断剩余拣货单数量
                        flag -= 1
                        if flag:
                            input("此订单还有剩余拣货单，请完成拣货作业后,按y/n抢单:\t")
                    else:
                        print(f"订单{order}完成抢单\n")
                        tb.clear_rows()  # 清空表单数据
                        break

                # 等待订单下发
                elif order_info == 3:
                    if num == 6:
                        print("请确认订单派单后再进行抢单！！\n")
                        break
                    print("订单未派单到履约...\n")
                    time.sleep(2)
                    num += 1
                    continue
                else:
                    if order_info == 1:
                        print(f"订单{order}正在拣货，无需抢单\n")
                    else:
                        print(f"订单{order}已经完成拣货，无需抢单\n")

                    break
    except Exception as e:
        print(e)


if __name__ == '__main__':
    mainPicking()
    # a = Picking(1001)
    # print(a.code_26(3601349, 180))
    # b = MyDB("db03.beta1.fn", "su_freshpicking", "FG6tq8BGfc", "fresh_picking", 1001)
    # print(b.ifStoreType())
    # print(b.db_table)
    # print(b.getItemType(100120240605000002))
    # print(b.getPickArea("一点点拣货区"))
